unit Region;

interface

uses
  GlobalRecordsAndEnums,
  Classes;

type
  TRegion = class
    private
      _name: String;
      _id: Integer;
      _faction: EFaction;
    public
      constructor Create; overload;
      constructor Create(region: SRegion); overload;

      procedure Load(region: SRegion);
      function Save: SRegion;

      property Name: String read _name;
      property ID: Integer read _id;
      property Faction: EFaction read _faction;
  end;

  TRegions = class
    private
      _regions: TList;

      function LoadRegions_v043(stream: TMemoryStream): Boolean;
      function GetRegionCount: Integer;
    public
      constructor Create;
      destructor Destroy;

      procedure Add(region: TRegion);
      function GetRegion(index: Integer): TRegion;
      function GetRegionByID(ID: Integer): TRegion;
      procedure Clear;

      property Count: Integer read GetRegionCount;
  end;
  function SortRegion(Item1, Item2: Pointer): Integer;

implementation

uses
  SysUtils, Dialogs, Forms;

//=====================
//====== TRegion ======
//=====================

constructor TRegion.Create;
begin
  inherited Create;
  _name := 'New region';
  _id := -1;
  _faction := FAC_None;
end;

constructor TRegion.Create(region: SRegion);
begin
  inherited Create;
  _name := region.Name;
  _id := region.ID;
  _faction := region.Faction;
end;

procedure TRegion.Load(region: SRegion);
begin
  _name := region.Name;
  _id := region.ID;
  _faction := region.Faction;
end;

function TRegion.Save: SRegion;
begin
  result.Name := _name;
  result.ID := _id;
  result.Faction := _faction;
end;

//======================
//====== TRegions ======
//======================

function TRegions.GetRegionCount;
begin
  result := _regions.Count;
end;

constructor TRegions.Create;
var
  stream: TMemoryStream;
  version: Double;
begin
  _regions := TList.Create;
  if (not FileExists('res\Regions.dat')) then begin
    MessageDlg('Unable to locate the file ' + ExtractFileDir(Application.ExeName) + '\res\Regions.dat.', mtError, [mbOk], 0);
  end
  else begin
    stream := TMemoryStream.Create;
    stream.LoadFromFile('res\Regions.dat');
    stream.Position := 0;
    try
      stream.Read(version, sizeof(Double));
    except
      MessageDlg('Error reading Regions.dat: invalid version information.', mtError, [mbOk], 0);
      stream.Free;
      exit;
    end;
    if (Round(version * 100) = 43) then // just 0.43 seems to result in a precision error
      self.LoadRegions_v043(stream)
    else begin
      MessageDlg('Error reading Regions.dat: no suitable load function found.', mtError, [mbOk], 0);
    end;
    stream.Free;
    _regions.Sort(SortRegion);
  end;
end;

destructor TRegions.Destroy;
var
  i: Integer;
  stream: TMemoryStream;
  reg: SRegion;
  version: Double;
begin
  if (adminhax) then begin
    version := 0.43;
    stream := TMemoryStream.Create;
    stream.Write(version, SizeOf(Double));
    for i := 0 to _regions.Count -1 do begin
      reg := TRegion(_regions[i]).Save;
      stream.Write(reg, SizeOf(SRegion));
    end;
    try
      stream.SaveToFile('res\Regions.dat');
    except
      on e: Exception do MessageDlg(e.Message, mtError, [mbOk], 0);
    end;
    stream.Free;
  end;


  for i := 0 to _regions.Count -1 do begin
    TRegion(_regions.Items[i]).Destroy;
  end;
  _regions.Destroy;
  
  inherited Destroy;
end;

function TRegions.LoadRegions_v043(stream: TMemoryStream): Boolean;
var
  reg: SRegion;
begin
  result := true;
  while stream.Position < stream.Size do begin
    try
      stream.Read(reg, sizeof(SRegion));
      _regions.Add(TRegion.Create(reg));
    except
      MessageDlg('Error reading Regions.dat: invalid region', mtError, [mbOk], 0);
      result := false;
      exit;
    end;
  end;
end;

procedure TRegions.Add(region: TRegion);
begin
  _regions.Add(region);
end;

function TRegions.GetRegion(index: Integer): TRegion;
begin
  if (index < _regions.Count) then result := TRegion(_regions[index])
  else result := nil;
end;

function TRegions.GetRegionByID(ID: Integer): TRegion;
var
  i: Integer;
begin
  result := nil;
  for i := 0 to _regions.Count -1 do begin
    if (TRegion(_regions[i]).ID = ID) then begin
      result := TRegion(_regions[i]);
    end;
  end;
end;

function SortRegion(Item1, Item2: Pointer): Integer;
begin
  result := CompareText(TRegion(Item1).Name, TRegion(Item2).Name);
end;

procedure TRegions.Clear;
var
  i: Integer;
begin
  for i := 0 to _regions.Count -1 do begin
    TRegion(_regions[i]).Destroy;
  end;
  _regions.Destroy;

  _regions := TList.Create;
end;

end.
